#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>

using namespace std;

int main()
{
    int pipeFd[2];
    // 创建管道
    pipe(pipeFd);

    // 查看管道缓冲区的大小
    // fpathconf 是一个 POSIX 系统调用函数用于获取与文件相关的系统配置信息。
    // 它允许程序员查询一个文件或文件描述符的操作系统配置参数，例如最大允许文件名长度、最大允许路径长度等。
    // long fpathconf(int fd, int name);
    // fd: 文件描述符（file descriptor），表示需要查询的文件。
    // name: 需要查询的配置信息类型，可以是预定义的常量，如 _PC_NAME_MAX、_PC_PATH_MAX 等。
    cout << "pipe size:" << fpathconf(pipeFd[0], _PC_PIPE_BUF) << endl;; 
    cout << "pipe size:" << fpathconf(pipeFd[1], _PC_PIPE_BUF) << endl;;

    // 创建进程
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork error");
        exit(-1);
    }
    else if (pid == 0)
    {
        // 关闭写端
        close(pipeFd[1]);

        // 子进程
        // int recvMoney = 0;
        // int readBytes = read(pipeFd[0], &recvMoney, sizeof(recvMoney));
        // cout << "readBytes:" << readBytes << ", child recvMoney:" << recvMoney << endl;
        sleep(3);

        // 设置pipeFd[0]文件描述符为非阻塞：
        // 1、得到文件描述符的原本属性
        int flags = fcntl(pipeFd[0], F_GETFL);
        // 2、在原本的属性上面增加新的属性（非阻塞）
        flags |= O_NONBLOCK;
        // 3、设置附加上的属性到文件描述符
        fcntl(pipeFd[0], F_SETFL, flags);
        
        cout << "子进程, 从管道中读取数据..." << endl;

        char buffer[3] = { 0 };
        int readBytes = 0;
        while (1)
        {
            readBytes = read(pipeFd[0], buffer, sizeof(buffer) - 1);
            if (readBytes < 0)
            {
                // 如果错误信息是EAGAIN，这是人为制造的非阻塞
                if (errno == EAGAIN)
                {
                    cout << "non block..." << endl;
                }
                else
                {
                    perror("read error");
                }
                // 退出进程
                _exit(-1);     
            }
            if (readBytes < sizeof(buffer) - 1)
            {
                cout << "buffer:" << buffer << endl;
                break;
            }
            cout << "buffer:" << buffer << endl;
            memset(buffer, 0, sizeof(buffer));
        }
    }
    else
    {
        // 关闭读端
        close(pipeFd[0]);

        // 父进程
        // int money = 5000000;
        // 向管道写端写数据
        // write(pipeFd[1], static_cast<const void *>(&money), sizeof(money));

        cout << "父进程, 延时向管道写数据..." << endl;
        // 延时，让出CPU
        sleep(1);
        const char *data = "hello world.";
        write(pipeFd[1], static_cast<const void *>(data), strlen(data));

        // int recvMoney = 0;
        // read(pipeFd[0], &recvMoney, sizeof(recvMoney));
        // cout << "parent recvMoney:" << recvMoney << endl;

        // 回收子进程资源
        wait(NULL);
    }

    // 将程序卡在这的目的是为了方便开另一个终端查看进程信息
    // while (1)
    // {
    //     sleep(1);
    // }

    return 0;
}